package es

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/elastic/go-elasticsearch/v8/typedapi/core/search"
	"github.com/elastic/go-elasticsearch/v8/typedapi/core/update"
	"github.com/elastic/go-elasticsearch/v8/typedapi/some"
	"github.com/elastic/go-elasticsearch/v8/typedapi/types"
	"strconv"
	"studyElasticsearchDemo/model"
)

// Format系列函数实现了将给定类型数据格式化为string类型数据的功能。
// func FormatInt(i int64, base int) string:
// 返回i的base进制的字符串表示。base 必须在2到36之间，结果中会使用小写字母’a’到’z’表示大于10的数字。

// 对review的文档相关操作

// 1、创建文档

// CreateDocument  创建指定索引名称indexName的索引文档
func CreateDocument(review model.Review, indexName string) {

	// 添加文档
	resp, err := EsClient.Index(indexName).
		Id(strconv.FormatInt(review.ID, 10)). // 指定文档唯一ID
		Document(review).Do(context.Background())
	if err != nil {
		fmt.Printf("indexing document failed, err:%v\n", err)
		return
	}
	fmt.Printf("result:%#v\n", resp.Result)
}

// 2、根据文档唯一ID获取指定索引下的文档

// GetDocumentByDocId 根据文档Id获取指定索引下的文档
func GetDocumentByDocId(id string, indexName string) {
	resp, err := EsClient.Get(indexName, id).Do(context.Background())
	if err != nil {
		fmt.Printf("get document by id failed, err:%v\n", err)
		return
	}
	fmt.Printf("fileds:%s\n", resp.Source_)
}

// 3、检索document

// 3.1 检索全部文档

// SearchAllDocuments 检索 索引下的全部文档
func SearchAllDocuments(indexName string) {
	// 搜索文档
	resp, err := EsClient.Search().
		Index(indexName).
		Request(&search.Request{
			Query: &types.Query{
				MatchAll: &types.MatchAllQuery{},
			},
		}).
		Do(context.Background())
	if err != nil {
		fmt.Printf("search documents failed, err:%v\n", err)
		return
	}
	fmt.Printf("total:%d\n", resp.Hits.Total.Value)
	// 遍历所有结果
	for _, hit := range resp.Hits.Hits {
		fmt.Printf("%s\n", hit.Source_)
	}
}

// 3.2 模糊条件查询
// 在 my-review-1 中搜索 content 包含 “好评” 的文档

// SearchDocument 指定条件搜索指定index下的文档
func SearchDocument(indexName string) {
	// 搜索content中包含好评的文档
	resp, err := EsClient.Search().
		Index(indexName).
		Request(&search.Request{
			Query: &types.Query{
				MatchPhrase: map[string]types.MatchPhraseQuery{
					"content": {Query: "好评"},
				},
			},
		}).
		Do(context.Background())
	if err != nil {
		fmt.Printf("search document failed, err:%v\n", err)
		return
	}
	fmt.Printf("total: %d\n", resp.Hits.Total.Value)
	// 遍历所有结果
	for _, hit := range resp.Hits.Hits {
		fmt.Printf("%s\v", hit.Source_)
	}
}

// 3.3 聚合检索

// AggregationDemo 聚合
func AggregationDemo(indexName string) {
	// 在 my-review-1 上运行一个平均值聚合，得到所有文档 score 的平均值。
	avgScoreAgg, err := EsClient.Search().
		Index(indexName).
		Request(
			&search.Request{
				Size: some.Int(0),
				Aggregations: map[string]types.Aggregations{
					"avg_score": { // 将所有文档的 score的平均值聚合为 avg_score
						Avg: &types.AverageAggregation{
							Field: some.String("score"),
						},
					},
				},
			}).Do(context.Background())
	if err != nil {
		fmt.Printf("aggregation failed, err:%v\n", err)
		return
	}
	fmt.Printf("avgScore:%#v\n", avgScoreAgg.Aggregations["avg_score"])
}

// 4、更新文档

// UpdateDocument 更新文档
func UpdateDocument(review model.Review, indexName string) {
	// 修改后的结构体变量
	//d1 := Review{
	//	ID:      1,
	//	UserID:  147982601,
	//	Score:   5,
	//	Content: "这是一个修改后的好评！", // 有修改
	//	Tags: []Tag{ // 有修改
	//		{1000, "好评"},
	//		{9000, "有图"},
	//	},
	//	Status:      2,
	//	PublishTime: time.Now(),
	//}

	resp, err := EsClient.Update(indexName, fmt.Sprintf("%d", review.ID)). // 通过唯一文档ID指定要更新的文档
										Doc(review). // 使用结构体变量更新
										Do(context.Background())
	if err != nil {
		fmt.Printf("update document failed, err:%v\n", err)
		return
	}
	fmt.Printf("result:%v\n", resp.Result)
}

// 更新可以使用结构体变量也可以使用原始JSON字符串数据。

// UpdateDocumentByJson 更新文档
func UpdateDocumentByJson(docId, str, indexName string) {
	// 修改后的JSON字符串
	//str := `{
	// "id":1,
	// "userID":147982601,
	// "score":5,
	// "content":"这是一个二次修改后的好评！",
	// "tags":[
	//  {
	//   "code":1000,
	//   "title":"好评"
	//  },
	//  {
	//   "code":9000,
	//   "title":"有图"
	//  }
	// ],
	// "status":2,
	// "publishDate":"2023-12-16T15:27:18.219385+08:00"
	//}`

	// 直接使用JSON字符串更新

	resp, err := EsClient.Update(indexName, docId).
		Request(&update.Request{
			Doc: json.RawMessage(str),
		}).
		Do(context.Background())
	if err != nil {
		fmt.Printf("update document failed, err:%v\n", err)
		return
	}
	fmt.Printf("result:%v\n", resp.Result)
}

// 5、删除文档
// 5.1 根据ID删除文档

// DeleteDocument 删除 document
func DeleteDocument(docId, indexName string) {
	resp, err := EsClient.Delete(indexName, docId).
		Do(context.Background())
	if err != nil {
		fmt.Printf("delete document failed, err:%v\n", err)
		return
	}
	fmt.Printf("result:%v\n", resp.Result)
}
